﻿//---------------------------------------------------------------------------
// <copyright file="RibbonGallery.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Xml;
using Microsoft.Windows.Automation.Peers;
using Microsoft.Windows.Input;
using MS.Internal;

namespace Microsoft.Windows.Controls.Ribbon
{
	/// <summary>
	///   RibbonGallery inherits from ItemsControl. It contains RibbonGalleryCategory instances which in turn contain
	///   RibbonGalleryItem instances. 
	/// </summary>
	[StyleTypedProperty(Property = "AllFilterItemContainerStyle", StyleTargetType = typeof(RibbonMenuItem))]
	[StyleTypedProperty(Property = "FilterItemContainerStyle", StyleTargetType = typeof(RibbonMenuItem))]
	[StyleTypedProperty(Property = "GalleryItemStyle", StyleTargetType = typeof(RibbonGalleryItem))]
	[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonGalleryCategory))]
	[TemplatePart(Name = ItemsHostName, Type = typeof(ItemsPresenter))]
	[TemplatePart(Name = _filterMenuButtonTemplatePartName, Type = typeof(RibbonMenuButton))]
	[TemplatePart(Name = ScrollViewerTemplatePartName, Type = typeof(ScrollViewer))]
	[TemplatePart(Name = FilterContentPaneTemplatePartName, Type = typeof(ContentPresenter))]
	public class RibbonGallery : ItemsControl, IWeakEventListener, IPreviewCommandSource
	{
		#region Constructors

		/// <summary>
		///   Initializes static members of the RibbonGallery class.
		/// </summary>
		static RibbonGallery()
		{
			Type ownerType = typeof(RibbonGallery);
			DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));
			ItemContainerStyleProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceItemContainerStyle)));
			ItemTemplateProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceItemTemplate)));
			EventManager.RegisterClassHandler(ownerType, MouseMoveEvent, new MouseEventHandler(OnMouseMove), true);
			ToolTipProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(RibbonHelper.CoerceRibbonToolTip)));
			ToolTipService.ShowOnDisabledProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true));
			ContextMenuProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(RibbonHelper.OnContextMenuChanged, RibbonHelper.OnCoerceContextMenu));
			ContextMenuService.ShowOnDisabledProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true));
			EventManager.RegisterClassHandler(ownerType, RibbonControlService.DismissPopupEvent, new RibbonDismissPopupEventHandler(OnDismissPopupThunk));

			FilterCommand = new RoutedCommand("Filter", ownerType);
			CommandManager.RegisterClassCommandBinding(ownerType, new CommandBinding(FilterCommand, FilterExecuted, FilterCanExecute));
			EventManager.RegisterClassHandler(ownerType, LoadedEvent, new RoutedEventHandler(OnLoaded));
			EventManager.RegisterClassHandler(ownerType, UnloadedEvent, new RoutedEventHandler(OnUnloaded));
		}

		/// <summary>
		///   Initializes an instance of the RibbonGallery class.
		/// </summary>
		public RibbonGallery()
		{
			this.ItemContainerGenerator.StatusChanged += new EventHandler(OnItemContainerGeneratorStatusChanged);

			// Ensure coercion happens for these APIs.
			this.CoerceValue(FilterItemTemplateSelectorProperty);
			this.CoerceValue(FilterItemContainerStyleSelectorProperty);
		}

		#endregion

		#region Template

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();

			// remove any old handlers
			if (_filterMenuButton != null)
			{
				Debug.Assert(_filterMenuButton.ItemContainerGenerator != null);
				_filterMenuButton.ItemContainerGenerator.StatusChanged -= OnFilterButtonItemContainerGeneratorStatusChanged;
			}

			_filterMenuButton = this.Template.FindName(_filterMenuButtonTemplatePartName, this) as RibbonMenuButton;

			if (_filterMenuButton != null)
			{
				Debug.Assert(_filterMenuButton.ItemContainerGenerator != null);
				_filterMenuButton.ItemContainerGenerator.StatusChanged += new EventHandler(OnFilterButtonItemContainerGeneratorStatusChanged);
				Binding itemsSourceBinding = new Binding() { Source = this._categoryFilters };
				_filterMenuButton.SetBinding(RibbonMenuButton.ItemsSourceProperty, itemsSourceBinding);

				_filterMenuButton.Loaded += new RoutedEventHandler(filterMenuButton_Loaded);
			}

			_itemsPresenter = (ItemsPresenter)GetTemplateChild(ItemsHostName);
			_filterContentPane = GetTemplateChild(FilterContentPaneTemplatePartName) as ContentPresenter;
			_scrollViewer = GetTemplateChild(RibbonGallery.ScrollViewerTemplatePartName) as ScrollViewer;
		}

		#region CurrentFilterItem

		// Once the filterMenuButton is loaded, its template is available and we can find the ContentPresenter that
		// hosts the current filter.  We must bind our FilterItemTemplateSelector so that the current filter, hosted in a RibbonToggleButton,
		// displays the same way as the filters themselves, which are RibbonMenuItems.
		private void filterMenuButton_Loaded(object sender, RoutedEventArgs e)
		{
			_filterMenuButton.Loaded -= new RoutedEventHandler(filterMenuButton_Loaded);

			RibbonToggleButton filterToggleButton = _filterMenuButton.Template.FindName(RibbonMenuButton.ToggleButtonTemplatePartName, _filterMenuButton) as RibbonToggleButton;
			if (filterToggleButton != null)
			{
				Binding currentFilterBinding = new Binding("CurrentFilter") { Source = this };
				filterToggleButton.SetBinding(RibbonToggleButton.ContentProperty, currentFilterBinding);

				// Find the RibbonMenuItem for the filter itself so that we can template it.
				// We need to set the following bindings on it:
				//  - DataContext --> CurrentFilter
				//  - Style --> CurrentFilterStyle
				//  - Header --> CurrentFilterHeader  (plus some extra handling for when CurrentFilterHeader is of type BindingBase; see its coercion)
				//  - Template --> CurrentFilterTemplate 
				_currentFilterItem = filterToggleButton.Template.FindName("CurrentFilterItem", filterToggleButton) as RibbonMenuItem;
				if (_currentFilterItem != null)
				{
					// DataContext --> CurrentFilter
					_currentFilterItem.SetBinding(RibbonMenuItem.DataContextProperty, currentFilterBinding);

					// Style --> CurrentFilterStyle
					Binding currentFilterStyleBinding = new Binding("CurrentFilterStyle") { Source = this };
					_currentFilterItem.SetBinding(RibbonMenuItem.StyleProperty, currentFilterStyleBinding);

					// Header --> CurrentFilterHeader
					this.SetHeaderBindingForCurrentFilterItem();

					// Template --> CurrentFilterTemplate
					this.SetTemplateBindingForCurrentFilterItem();
				}
			}

			PropertyHelper.TransferProperty(this, ContextMenuProperty);   // Coerce to get a default ContextMenu if none has been specified.
			PropertyHelper.TransferProperty(this, RibbonControlService.CanAddToQuickAccessToolBarDirectlyProperty);
		}

		private static readonly DependencyProperty CurrentFilterStyleProperty =
			DependencyProperty.Register("CurrentFilterStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(null, null, OnCoerceCurrentFilterStyle));

		private Style CurrentFilterStyle
		{
			get { return (Style)GetValue(CurrentFilterStyleProperty); }
		}

		// coercion precedence:
		//  1) FilterItemContainerStyleSelector, if one is specified.
		//  2) FilterItemContainerStyle/AllFilterItemContainerStyle, if specified.
		//  3) null (the base value)
		// We get this all for free thanks to the coercion on FilterItemContainerStyleSelector and the logic in the default StyleSelector.
		// We just need to tell the following properties to call this coercion when they change:
		//  1) FilterItemContainerStyleSelector
		//  2) FilterItemContainerStyle
		//  3) AllFilterItemContainerStyle
		//  4) CurrentFilter
		private static object OnCoerceCurrentFilterStyle(DependencyObject d, object baseValue)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			if (gallery.CurrentFilter != null)
			{
				return gallery.FilterItemContainerStyleSelector.SelectStyle(gallery.CurrentFilter, gallery._currentFilterItem);
			}
			return null;
		}

		// Header is tricky.  For the filter items, Header defaults to the DataContext.
		// However, Header can be overridden by a Setter at a the ItemContainerStyle level.
		// Therefore, we should only bind Header to CurrentFilter when no Style is setting Header.
		// We need to re-run this logic whenever any of the following change:
		//  1) FilterItemContainerStyleSelector
		//  2) FilterItemContainerStyle
		//  3) AllFilterItemContainerStyle
		//  4) CurrentFilter
		// We also need to run this logic in OnApplyTemplate AFTER Style bindings have been set up.
		private void SetHeaderBindingForCurrentFilterItem()
		{
			if (_currentFilterItem != null)
			{
				_currentFilterItem.ClearValue(RibbonMenuItem.HeaderProperty);

				if (PropertyHelper.IsDefaultValue(_currentFilterItem, RibbonMenuItem.HeaderProperty))
				{
					// In the default case (where no Style is setting Header), we fall back
					// to setting _currentFilterItem.Header to CurrentFilter.
					_currentFilterItem.Header = this.CurrentFilter;
				}
			}
		}

		private static readonly DependencyProperty CurrentFilterTemplateProperty =
			DependencyProperty.Register("CurrentFilterTemplate", typeof(DataTemplate), typeof(RibbonGallery),
				new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnCurrentFilterTemplateChanged), new CoerceValueCallback(OnCoerceCurrentFilterTemplate)));

		private DataTemplate CurrentFilterTemplate
		{
			get { return (DataTemplate)GetValue(CurrentFilterTemplateProperty); }
		}

		private static void OnCurrentFilterTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			gallery.SetTemplateBindingForCurrentFilterItem();
		}

		private bool FilterMenuButtonTemplateIsBound
		{
			get { return _bits[(int)Bits.FilterMenuButtonTemplateIsBound]; }
			set { _bits[(int)Bits.FilterMenuButtonTemplateIsBound] = value; }
		}

		// This method sets up a binding between the FilterMenuButton's hosted RibbonMenuItem.HeaderTemplate and CurrentFilterTemplate.
		// We need to call it whenever RibbonGallery is retemplated or CurrentFilterTemplate changes.
		// If CurrentFilterTemplate is not being acquired through a user-set value, we do not want to have this binding.  That way,
		// a Setter for HeaderTemplate in the FilterMenuButton's Style, if present, will be honored.
		private void SetTemplateBindingForCurrentFilterItem()
		{
			if (_currentFilterItem == null)
			{
				return;
			}

			// Assume we are not going to set up a binding for template.  The user may using FilterItemContainerStyle with a Setter
			// for HeaderTemplate.  In this case, we need to honor that setter so long as an item template for the filter has not
			// been set through one of the other APIs: FilterItemTemplate, AllFilterItemTemplate, FilterItemTemplateSelector.
			// Thus, only set this binding on HeaderTemplate when one of those template APIs is specified.  When a template for the filter item
			// is not specified, we unset this binding so that a Setter for HeaderTemplate in the Style is able to bleed through.
			bool templateShouldBeBound = false;

			if (FilterItemTemplateSelector is RibbonGalleryDefaultFilterItemTemplateSelector)
			{
				if (object.ReferenceEquals(CurrentFilter, AllFilterItem))
				{
					if (this.AllFilterItemTemplate != null)
					{
						templateShouldBeBound = true;
					}
				}
				else
				{
					if (this.FilterItemTemplate != null)
					{
						templateShouldBeBound = true;
					}
				}
			}
			else
			{
				// Someone is setting FilterItemTemplateSelector.  We should bind to the template that gets selected.
				templateShouldBeBound = true;
			}

			if (templateShouldBeBound && !FilterMenuButtonTemplateIsBound)
			{
				Binding currentFilterTemplateBinding = new Binding("CurrentFilterTemplate") { Source = this };
				_currentFilterItem.SetBinding(RibbonMenuItem.HeaderTemplateProperty, currentFilterTemplateBinding);
				FilterMenuButtonTemplateIsBound = true;
			}
			else if (!templateShouldBeBound && FilterMenuButtonTemplateIsBound)
			{
				BindingOperations.ClearBinding(_currentFilterItem, RibbonMenuItem.HeaderTemplateProperty);
				FilterMenuButtonTemplateIsBound = false;
			}
		}

		// coercion precedence:
		//  1) FilterItemTemplateSelector, if one is specified.
		//  2) FilterItemTemplate/AllFilterItemTemplate, if specified.
		//  3) null (the base value)
		// We get this all for free thanks to the coercion on FilterItemTemplateSelector and the logic in the default DataTemplateSelector.
		// We just need to tell the following properties to call this coercion when they change:
		//  1) FilterItemTemplateSelector
		//  2) FilterItemTemplate
		//  3) AllFilterItemTemplate
		//  4) CurrentFilter
		private static object OnCoerceCurrentFilterTemplate(DependencyObject d, object baseValue)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			if (gallery.CurrentFilter != null)
			{
				return gallery.FilterItemTemplateSelector.SelectTemplate(gallery.CurrentFilter, gallery._currentFilterItem);
			}
			return null;
		}

		private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e)
		{
			if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
			{
				RepopulateCategoryFilters();
				SynchronizeWithCurrentItem();

				if (_itemsPresenter != null)
				{
					ItemsHostSite = (Panel)(ItemsPanel.FindName(RibbonGallery.ItemsHostPanelName, _itemsPresenter));
				}
			}
		}

		#endregion CurrentFilterItem


		private void OnFilterButtonItemContainerGeneratorStatusChanged(object sender, EventArgs e)
		{
			if (_filterMenuButton.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
			{
				foreach (object filter in this._categoryFilters)
				{
					RibbonMenuItem filterItem = _filterMenuButton.ItemContainerGenerator.ContainerFromItem(filter) as RibbonMenuItem;

					// Bind filterItem.IsChecked to true when Object.ReferenceEquals(this.CurrentFilter, filterItem.DataContext).
					MultiBinding isCheckedBinding = new MultiBinding();
					isCheckedBinding.Converter = new ReferentialEqualityConverter();
					Binding currentFilterBinding = new Binding("CurrentFilter") { Source = this };
					Binding myHeaderBinding = new Binding("DataContext") { Source = filterItem };
					isCheckedBinding.Bindings.Add(currentFilterBinding);
					isCheckedBinding.Bindings.Add(myHeaderBinding);
					filterItem.SetBinding(RibbonMenuItem.IsCheckedProperty, isCheckedBinding);

					// Set up FilterCommand properties.
					filterItem.Command = RibbonGallery.FilterCommand;

					Binding commandParameterBinding = new Binding("DataContext") { RelativeSource = new RelativeSource(RelativeSourceMode.Self) };
					filterItem.SetBinding(RibbonMenuItem.CommandParameterProperty, commandParameterBinding);
				}
			}
		}

		#endregion Template

		#region Tree

		// To fetch defined ItemsPanel in RibbonGalleryCategory's Template. It is set during ApplyTemplate.
		internal Panel ItemsHostSite
		{
			get;
			private set;
		}

		#endregion

		#region Layout

		/// <summary>
		/// MinColumnCount is the property defined on RibbonGallery. RibbonGalleryCategory also Adds
		/// itself Owner to this property.
		/// It's used by RibbonGalleryItemsPanel during Measure/Arrange which is default panel for RibbonGalleryCategory
		/// Default is 0
		/// </summary>
		public int MinColumnCount
		{
			get { return (int)GetValue(MinColumnCountProperty); }
			set { SetValue(MinColumnCountProperty, value); }
		}

		/// <summary>
		/// MinColumnCount is the property defined on RibbonGallery. RibbonGalleryCategory also Adds
		/// itself Owner to this property.
		/// It's used by RibbonGalleryItemsPanel during Measure/Arrange which is default panel for RibbonGalleryCategory
		/// Default is 0
		/// </summary>
		public static readonly DependencyProperty MinColumnCountProperty =
			DependencyProperty.Register(
							"MinColumnCount",
							typeof(int),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnLayoutPropertyChange)), new ValidateValueCallback(IsMinMaxColumnCountValid));

		/// <summary>
		/// MaxColumnCount is the property defined on RibbonGallery. RibbonGalleryCategory also Adds
		/// itself Owner to this property.
		/// It's used by RibbonGalleryItemsPanel during Measure/Arrange which is default panel for RibbonGalleryCategory
		/// Default is int.MaxValue
		/// </summary>
		public int MaxColumnCount
		{
			get { return (int)GetValue(MaxColumnCountProperty); }
			set { SetValue(MaxColumnCountProperty, value); }
		}

		/// <summary>
		/// MaxColumnCount is the property defined on RibbonGallery. RibbonGalleryCategory also Adds
		/// itself Owner to this property.
		/// It's used by RibbonGalleryItemsPanel during Measure/Arrange which is default panel for RibbonGalleryCategory
		/// Default is int.MaxValue
		/// </summary>
		public static readonly DependencyProperty MaxColumnCountProperty =
			DependencyProperty.Register(
							"MaxColumnCount",
							typeof(int),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(
								int.MaxValue,
								FrameworkPropertyMetadataOptions.AffectsMeasure,
								new PropertyChangedCallback(OnLayoutPropertyChange),
								new CoerceValueCallback(CoerceMaxColumnCount)),
							new ValidateValueCallback(IsMinMaxColumnCountValid));

		// coerce MaxColumnCount so as it's never lesser than MinColumnCount
		private static object CoerceMaxColumnCount(DependencyObject d, object baseValue)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			int minColCount = gallery.MinColumnCount;
			if (minColCount > (int)baseValue)
				return minColCount;
			return baseValue;
		}

		private static bool IsMinMaxColumnCountValid(object value)
		{
			int v = (int)value;
			return (v > 0);
		}

		/// <summary>
		/// When ColumnsStretchToFill is true, RibbonGalleryItems are stretched during layout to occupy all the width available. 
		/// ColumnsStretchToFill is honored only when IsSharedColumnSizeScope is true.
		/// </summary>
		public bool ColumnsStretchToFill
		{
			get { return (bool)GetValue(ColumnsStretchToFillProperty); }
			set { SetValue(ColumnsStretchToFillProperty, value); }
		}

		public static readonly DependencyProperty ColumnsStretchToFillProperty = DependencyProperty.Register("ColumnsStretchToFill",
																										typeof(bool),
																										typeof(RibbonGallery),
																										new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnLayoutPropertyChange)));

		/// <summary>
		/// IsSharedColumnSizeScope: defined on RibbonGallery. RibbonGalleryCategory also adds itself owner to it.
		/// It's a BooleanProperty where True means that I(the control on which property is set) am the Scope for 
		/// Uniform layout of items. Truth Table for this could be defined by:
		/// (gallery.IsSharedColumnScope && !category.ISSharedColumnScope)? Gallery Scope  : Category Scope
		///  Default Scope must result as Gallery scope hence default value on Gallery is True and on Category it's false. 
		/// </summary>
		public bool IsSharedColumnSizeScope
		{
			get { return (bool)GetValue(IsSharedColumnSizeScopeProperty); }
			set { SetValue(IsSharedColumnSizeScopeProperty, value); }
		}

		/// <summary>
		///     IsSharedColumnSizeScope: defined on RibbonGallery. RibbonGalleryCategory also adds itself owner to it.
		///     It's a BooleanProperty where True means that I(the control on which property is set) am the Scope for 
		///     Uniform layout of items. Truth Table for this could be defined by:
		///     (gallery.IsSharedColumnScope && !category.ISSharedColumnScope)? Gallery Scope  : Category Scope
		///     Default Scope must result as Gallery scope hence default value on Gallery is True and on Category it's false. 
		/// </summary>
		public static readonly DependencyProperty IsSharedColumnSizeScopeProperty =
			DependencyProperty.Register(
							"IsSharedColumnSizeScope",
							typeof(bool),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnLayoutPropertyChange)));

		// MaxColumnWidth is the desired maximum width of any RibbonGalleryItem in this RibbonGallery for all the Categories 
		// whose Panel's uniform layout scope results in scope of gallery.
		internal double MaxColumnWidth
		{
			get { return (double)GetValue(MaxColumnWidthProperty); }
			set { SetValue(MaxColumnWidthProperty, value); }
		}

		// MaxColumnWidth is the desired maximum width of any RibbonGalleryItem in this RibbonGallery for all the Categories 
		// whose Panel's uniform layout scope results in scope of gallery.
		internal static readonly DependencyProperty MaxColumnWidthProperty =
			DependencyProperty.Register(
							"MaxColumnWidth",
							typeof(double),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(OnLayoutPropertyChange)));

		/// <summary>
		/// The actual width at which a GalleryItem in a SharedScope is arranged. 
		/// Its calculated such that the remaining horizontal space in the parent panel is filled up. 
		/// ArrangeWidth is recalculated whenever MaxColumnWidth changes.
		/// </summary>
		internal double ArrangeWidth
		{
			get;
			set;
		}

		/// <summary>
		/// Flag to indicate that ArrangeWidth should be recalculated because MaxColumnWidth changed.
		/// </summary>
		internal bool IsArrangeWidthValid
		{
			get;
			set;
		}

		/// <summary>
		/// Flag to indicate that MaxColumnWidth should be recalculated. for e.g. when Items collection changes. 
		/// </summary>
		internal bool IsMaxColumnWidthValid
		{
			get;
			set;
		}

		// This is a PropertyChangedCallBack for the layout related properties MinColumnCount/MaxColumnCount
		// IsSharedColumnScope and MaxColumnWidth on RibbonGallery. This calls InvalidateMeasure for all the
		// categories' ItemsPanel and they must use changed values.
		private static void OnLayoutPropertyChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery me = (RibbonGallery)d;
			me.IsArrangeWidthValid = false;
			me.InvalidateMeasureOnAllCategoriesPanel();
		}

		// Invalidate Measure on all the Categories' panel.
		internal void InvalidateMeasureOnAllCategoriesPanel()
		{
			if (Items != null)
			{
				for (int i = 0; i < Items.Count; i++)
				{
					RibbonGalleryCategory category = (RibbonGalleryCategory)ItemContainerGenerator.ContainerFromIndex(i);
					if (category != null)
					{
						if (category.ItemsHostSite != null)
						{
							TreeHelper.InvalidateMeasureForVisualAncestorPath<RibbonGallery>(category.ItemsHostSite, false);
						}
					}
				}
			}
		}

		#endregion Layout

		#region Selection

		/// <summary>
		///     Event fired when <see cref="SelectedItem"/> changes.
		/// </summary>
		public static readonly RoutedEvent SelectionChangedEvent =
			EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<object>), typeof(RibbonGallery));

		/// <summary>
		///     Event fired when <see cref="SelectedItem"/> changes.
		/// </summary>
		public event RoutedPropertyChangedEventHandler<object> SelectionChanged
		{
			add
			{
				AddHandler(SelectionChangedEvent, value);
			}

			remove
			{
				RemoveHandler(SelectionChangedEvent, value);
			}
		}

		/// <summary>
		///     Called when <see cref="SelectedItem"/> changes.
		///     Default implementation fires the <see cref="SelectionChanged"/> event.
		/// </summary>
		/// <param name="e">Event arguments.</param>
		protected virtual void OnSelectionChanged(RoutedPropertyChangedEventArgs<object> e)
		{
			RaiseEvent(e);

			if (ShouldExecuteCommand && !e.Handled && e.NewValue != null)
			{
				CommandHelpers.InvokeCommandSource(CommandParameter, PreviewCommandParameter, this, CommandOperation.Execute);
			}
		}

		// There are times when the SelectedItem and the HighlightedItem 
		// are being mutated temporarily. This is specifically the case 
		// with RibbonComboBox's use of the RibbonGallery. At this time 
		// we do not want to fire the Commands.

		internal bool ShouldExecuteCommand
		{
			get { return _bits[(int)Bits.ShouldExecuteCommand]; }
			set { _bits[(int)Bits.ShouldExecuteCommand] = value; }
		}

		/// <summary>
		///     The DependencyProperty for the <see cref="SelectedItem"/> property.
		///     Default Value: null
		/// </summary>
		public static readonly DependencyProperty SelectedItemProperty =
					DependencyProperty.Register(
										"SelectedItem",
										typeof(object),
										typeof(RibbonGallery),
										new FrameworkPropertyMetadata(
												null,
												FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
												null,
												new CoerceValueCallback(CoerceSelectedItem)));


		/// <summary>
		///     Specifies the selected item.
		/// </summary>
		public object SelectedItem
		{
			get
			{
				return GetValue(SelectedItemProperty);
			}
			set
			{
				SetValue(SelectedItemProperty, value);
			}
		}

		private bool ShouldForceCoerceSelectedItem
		{
			get { return _bits[(int)Bits.ShouldForceCoerceSelectedItem]; }
			set { _bits[(int)Bits.ShouldForceCoerceSelectedItem] = value; }
		}

		// To force Coercion even if the SelectionItem didn't change, useful in case of when ItemsCollection changes.
		internal void ForceCoerceSelectedItem()
		{
			try
			{
				ShouldForceCoerceSelectedItem = true;
				CoerceValue(SelectedItemProperty);
			}
			finally
			{
				ShouldForceCoerceSelectedItem = false;
			}
		}

		private static object CoerceSelectedItem(DependencyObject d, object value)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			if (!gallery.IsSelectionChangeActive)
			{
				object oldItem = gallery.SelectedItem;
				object newItem = value;

				if (!VerifyEqual(oldItem, newItem))
				{
					if (newItem != null)
					{
						RibbonGalleryCategory category = null;
						RibbonGalleryItem galleryItem = null;

						// If the newItem doesn't exist in RibbonGallery under any category then return UnsetValue
						// so as not to change existing value
						bool ignoreItemContainerGeneratorStatus = false;
						if (!gallery.ContainsItem(newItem, ignoreItemContainerGeneratorStatus, out category, out galleryItem))
						{
							return DependencyProperty.UnsetValue;
						}

						// Changes the selection to newItem
						gallery.ChangeSelection(newItem, galleryItem, true);
					}
					else
					{
						// Deselect oldItem
						gallery.ChangeSelection(oldItem, null, false);
					}
				}
				else if (gallery.ShouldForceCoerceSelectedItem)
				{
					RibbonGalleryCategory category = null;
					RibbonGalleryItem galleryItem = null;

					// This block is called when ItemCollection changes either at the Gallery or the Category levels
					// to handle the case that a previously SelectedItem is removed or replaced.
					bool ignoreItemContainerGeneratorStatus = true;
					if (!gallery.ContainsItem(newItem, ignoreItemContainerGeneratorStatus, out category, out galleryItem))
					{
						// Deselect oldItem
						value = null;
						gallery.ChangeSelection(oldItem, null, false);
					}
				}
			}

			return value;
		}

		/// <summary>
		///     The DependencyProperty for the <see cref="SelectedValue"/> property.
		///     Default Value: null
		/// </summary>
		public static readonly DependencyProperty SelectedValueProperty =
					DependencyProperty.Register(
										"SelectedValue",
										typeof(object),
										typeof(RibbonGallery),
										new FrameworkPropertyMetadata(
												null,
												FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
												null,
												new CoerceValueCallback(CoerceSelectedValue)));

		/// <summary>
		///     Specifies the value on the selected item as defined by <see cref="SelectedValuePath" />.
		/// </summary>
		public object SelectedValue
		{
			get
			{
				return GetValue(SelectedValueProperty);
			}
			set
			{
				SetValue(SelectedValueProperty, value);
			}
		}

		private bool ShouldForceCoerceSelectedValue
		{
			get { return _bits[(int)Bits.ShouldForceCoerceSelectedValue]; }
			set { _bits[(int)Bits.ShouldForceCoerceSelectedValue] = value; }
		}

		// To force Coercion even if the SelectionValue didn't change, useful when synchronizing 
		// SelectedItem after container generation is complete.
		internal void ForceCoerceSelectedValue()
		{
			try
			{
				ShouldForceCoerceSelectedValue = true;
				CoerceValue(SelectedValueProperty);
			}
			finally
			{
				ShouldForceCoerceSelectedValue = false;
			}
		}

		private static object CoerceSelectedValue(DependencyObject d, object value)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			if (!gallery.IsSelectionChangeActive)
			{
				object oldValue = gallery.SelectedValue;
				object newValue = value;

				if (!VerifyEqual(oldValue, newValue))
				{
					if (newValue != null)
					{
						object newItem;
						RibbonGalleryCategory category = null;
						RibbonGalleryItem galleryItem = null;

						// If the newValue doesn't exist in RibbonGallery under any category then return UnsetValue
						// so as not to change existing value
						bool ignoreItemContainerGeneratorStatus = false;
						if (!gallery.ContainsValue(value, ignoreItemContainerGeneratorStatus, out newItem, out category, out galleryItem))
						{
							return DependencyProperty.UnsetValue;
						}

						// Changes the selection to newItem
						gallery.SelectedItem = newItem;
					}
					else
					{
						// Deselect
						gallery.SelectedItem = null;
					}
				}
				else if (gallery.ShouldForceCoerceSelectedValue)
				{
					object newItem;
					RibbonGalleryCategory category = null;
					RibbonGalleryItem galleryItem = null;

					// This block is called when generating RibbonGalleryCategory containers
					// to synchronize the SelectedItem with the previously specified SelectedValue. 
					// If a match isn't found yet we keep the oldValue as is by returning UnsetValue.
					bool ignoreItemContainerGeneratorStatus = true;
					if (!gallery.ContainsValue(value, ignoreItemContainerGeneratorStatus, out newItem, out category, out galleryItem))
					{
						return DependencyProperty.UnsetValue;
					}
					gallery.SelectedItem = newItem;
				}
			}

			return value;
		}

		/// <summary>
		///     SelectedValuePath DependencyProperty
		/// </summary>
		public static readonly DependencyProperty SelectedValuePathProperty =
				DependencyProperty.Register(
						"SelectedValuePath",
						typeof(string),
						typeof(RibbonGallery),
						new FrameworkPropertyMetadata(
								String.Empty,
								new PropertyChangedCallback(OnSelectedValuePathChanged)));

		/// <summary>
		///  The path used to retrieve the SelectedValue from the SelectedItem
		/// </summary>
		[Localizability(LocalizationCategory.NeverLocalize)] // not localizable
		public string SelectedValuePath
		{
			get { return (string)GetValue(SelectedValuePathProperty); }
			set { SetValue(SelectedValuePathProperty, value); }
		}

		private static void OnSelectedValuePathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			ValueSource valueSource = DependencyPropertyHelper.GetValueSource(gallery, RibbonGallery.SelectedValueProperty);

			if (valueSource.IsCoerced || gallery.SelectedValue != null)
			{
				gallery.CoerceValue(SelectedValueProperty);
			}
		}

		public static readonly DependencyProperty IsSynchronizedWithCurrentItemProperty =
			DependencyProperty.Register("IsSynchronizedWithCurrentItem", typeof(bool?), typeof(RibbonGallery),
			new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnIsSynchronizedWithCurrentItemChanged)));

		/// <summary>
		///   This flag chooses the synchronization behavior between the 
		///   SelectedItem and the CurrentItem for the associated CollectionView. 
		///   When null we choose the automatic behavior of synchronizing only 
		///   when bound to an explicit CollectionViewSource.
		/// </summary>
		public bool? IsSynchronizedWithCurrentItem
		{
			get { return (bool?)GetValue(IsSynchronizedWithCurrentItemProperty); }
			set { SetValue(IsSynchronizedWithCurrentItemProperty, value); }
		}

		private static void OnIsSynchronizedWithCurrentItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			gallery.UpdateIsSynchronizedWithCurrentItemInternal();
		}

		/// <summary>
		///   Update the private flag IsSynchronizedWithCurrentItemInternal so that it 
		///   honor the public property when set and chooses the automatic behavior 
		///   which is synchornize currency only when bound to an explicit CollectionViewSource.
		/// </summary>
		private void UpdateIsSynchronizedWithCurrentItemInternal()
		{
			bool oldValue = IsSynchronizedWithCurrentItemInternal;
			if (oldValue)
			{
				// Stop listening for currency changes
				RemoveCurrentItemChangedListener();
			}

			bool? isSynchronizedWithCurrentItem = IsSynchronizedWithCurrentItem;
			if (isSynchronizedWithCurrentItem.HasValue)
			{
				IsSynchronizedWithCurrentItemInternal = isSynchronizedWithCurrentItem.Value;
			}
			else
			{
				IsSynchronizedWithCurrentItemInternal = IsInitialized && (RibbonGallery.GetSourceCollectionView(this) != null);
			}


			bool newValue = IsSynchronizedWithCurrentItemInternal;
			if (newValue)
			{
				// Listen for currency changes
				AddCurrentItemChangedListener();

				// Synchronize
				SynchronizeWithCurrentItem();
			}

			if (oldValue != newValue)
			{
				// Notify categories
				for (int i = 0; i < Items.Count; i++)
				{
					RibbonGalleryCategory category = ItemContainerGenerator.ContainerFromIndex(i) as RibbonGalleryCategory;
					if (category != null)
					{
						if (newValue)
						{
							category.AddCurrentItemChangedListener();
						}
						else
						{
							category.RemoveCurrentItemChangedListener();
						}
					}
				}
			}
		}

		internal bool IsSynchronizedWithCurrentItemInternal
		{
			get { return _bits[(int)Bits.IsSynchronizedWithCurrentItemInternal]; }
			set { _bits[(int)Bits.IsSynchronizedWithCurrentItemInternal] = value; }
		}

		private void SynchronizeWithCurrentItem()
		{
			if (IsSynchronizedWithCurrentItemInternal)
			{
				object selectedItem = SelectedItem;
				if (selectedItem != null)
				{
					// If there is a SelectedItem synchronize 
					// CurrentItem to match it
					RibbonGalleryCategory category;
					RibbonGalleryItem galleryItem;
					bool ignoreItemContainerGeneratorStatus = false;
					if (ContainsItem(selectedItem, ignoreItemContainerGeneratorStatus, out category, out galleryItem))
					{
						SynchronizeWithCurrentItem(category, selectedItem);
					}
				}
				else
				{
					// Since there isn't already a SelectedItem 
					// synchronize it to match CurrentItem
					//
					// It is possible that the RibbonGalleryCategory containers 
					// haven't been generated at the time that we attempt this 
					// synchronization. In such a case we retry when the 
					// containers have been generated.
					if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
					{
						OnCurrentItemChanged();
					}

					OnSourceCollectionViewCurrentItemChanged();
				}
			}
		}

		private void SynchronizeWithCurrentItem(
			RibbonGalleryCategory category,
			object selectedItem)
		{
			Debug.Assert(selectedItem != null, "Must have a selectedItem to synchronize with.");

			if (category != null)
			{
				// Synchronize currency on the category containing the SelectedItem
				MoveCurrentTo(category.CollectionView, selectedItem);

				// Synchronize currency on the gallery to be the category containing the SelectedItem
				MoveCurrentTo(CollectionView, ItemContainerGenerator.ItemFromContainer(category));
			}

			// Synchronize currency on the source CollectionView to be the SelectedItem
			int index = SourceCollectionView != null ? SourceCollectionView.IndexOf(selectedItem) : -1;
			if (index > -1)
			{
				MoveCurrentToPosition(SourceCollectionView, index);
			}
		}

		protected override void OnInitialized(EventArgs e)
		{
			base.OnInitialized(e);
			UpdateIsSynchronizedWithCurrentItemInternal();
		}

		protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
		{
			base.OnItemsSourceChanged(oldValue, newValue);
			UpdateIsSynchronizedWithCurrentItemInternal();

			// Note that it is possible that we haven't had a chance to sync 
			// to the CurrentItem on the CollectionView yet. This could happen, 
			// if the ItemContainers were generated synchronously and the base 
			// implementation fired ItemContainerGeneratorStatusChanged before 
			// we got here. So this is one more attempt to keep things in sync.

			SynchronizeWithCurrentItem();
		}

		private void AddCurrentItemChangedListener()
		{
			Debug.Assert(IsSynchronizedWithCurrentItemInternal, "We should add currency change listeners only when IsSynchronizedWithCurrentItemInternal is true");

			CollectionView = Items;
			SourceCollectionView = RibbonGallery.GetSourceCollectionView(this);

			if (SourceCollectionView == CollectionView.SourceCollection)
			{
				// We need to track the SourceCollectionView only if it 
				// is distinct from the immediate CollectionView
				SourceCollectionView = null;
			}

			// Listen for currency changes on the immediate CollectionView for the Gallery
			CurrentChangedEventManager.AddListener(CollectionView, this);

			// Listen for currency changes on the Source CollectionView of the Gallery
			if (SourceCollectionView != null)
			{
				CurrentChangedEventManager.AddListener(SourceCollectionView, this);
			}
		}

		private void RemoveCurrentItemChangedListener()
		{
			// Stop listening for currency changes on the immediate CollectionView for the Gallery
			if (CollectionView != null)
			{
				CurrentChangedEventManager.RemoveListener(CollectionView, this);
				CollectionView = null;
			}

			// Stop listening for currency changes on the Source CollectionView of the Gallery
			if (SourceCollectionView != null)
			{
				CurrentChangedEventManager.RemoveListener(SourceCollectionView, this);
				SourceCollectionView = null;
			}
		}

		internal CollectionView CollectionView
		{
			get;
			set;
		}

		internal CollectionView SourceCollectionView
		{
			get;
			set;
		}

		bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
		{
			if (managerType == typeof(CurrentChangedEventManager))
			{
				if (sender == CollectionView)
				{
					// Update currency on the immediate CollectionView for the Gallery
					OnCurrentItemChanged();
				}
				else
				{
					// Update currency on the Source CollectionView of the Gallery
					OnSourceCollectionViewCurrentItemChanged();
				}
			}
			else
			{
				// Unrecognized event
				return false;
			}

			return true;
		}

		// Update currency on the immediate CollectionView for the Gallery
		private void OnCurrentItemChanged()
		{
			Debug.Assert(IsSynchronizedWithCurrentItemInternal, "We shouldn't be listening for currency changes if IsSynchronizedWithCurrentItemInternal is false");

			if (CollectionView == null || IsSelectionChangeActive)
			{
				return;
			}

			// Synchronize the SelectedItem to be the first Item 
			// within the current Category.
			RibbonGalleryCategory category = this.ItemContainerGenerator.ContainerFromItem(CollectionView.CurrentItem) as RibbonGalleryCategory;
			if (category != null && category.Items.Count > 0)
			{
				SelectedItem = category.Items[0];
			}
		}

		// Update currency on the Source CollectionView of the Gallery
		private void OnSourceCollectionViewCurrentItemChanged()
		{
			Debug.Assert(IsSynchronizedWithCurrentItemInternal, "We shouldn't be listening for currency changes if IsSynchronizedWithCurrentItemInternal is false");

			if (IsSelectionChangeActive)
			{
				return;
			}

			// Synchronize SelectedItem with the CurrentItem 
			// of the Source CollectionView
			if (SourceCollectionView != null)
			{
				SelectedItem = SourceCollectionView.CurrentItem;
			}
		}

		// This is to handle the case where the Gallery is bound to the Groups 
		// property of a CollectionViewSource with GroupDescriptions. Consider 
		// this example. 
		//
		// <RibbonGallery 
		//  Name="rg"
		//  IsSynchronizedWithCurrentItem="True"
		//  Grid.Row="1"
		//  Grid.Column="0"
		//  ItemsSource="{Binding Source={StaticResource CitiesCVS},Path=Groups}"
		//  ItemTemplate="{StaticResource HDT2}" />
		// <ListBox 
		//  Name="lb"
		//  SelectionMode="Single"
		//  IsSynchronizedWithCurrentItem="True"
		//  Grid.Row="1"
		//  Grid.Column="1"
		//  ItemsSource="{Binding Source={StaticResource CitiesCVS}}"
		//  ItemTemplate="{StaticResource CT2}"/>
		//
		// To keep the ListBox synchronized with the Gallery we will need to update currency on 
		// the CollectionView that the Listox is bound which in this case is the Source CollectionView 
		// for Groups collection that the Gallery is bound to.
		internal static CollectionView GetSourceCollectionView(ItemsControl itemsControl)
		{
			if (itemsControl == null)
				return null;

			CollectionViewSource cvs = null;
			CollectionView cv = null;
			Binding binding = BindingOperations.GetBinding(itemsControl, ItemsSourceProperty);
			if (binding != null)
			{
				cvs = binding.Source as CollectionViewSource;
				if (cvs != null)
				{
					cv = cvs.View as CollectionView;
				}
			}

			return cv;
		}

		// Update all selection properties viz. 
		// - SelectedItem 
		// - SelectedValue
		// - CurrentItem 
		// - IsSelected 
		// - SelectedContainers
		internal void ChangeSelection(object item, RibbonGalleryItem container, bool isSelected)
		{
			if (IsSelectionChangeActive)
			{
				return;
			}

			object oldItem = SelectedItem;
			object newItem = item;
			bool selectedItemChanged = !VerifyEqual(oldItem, newItem);

			try
			{
				IsSelectionChangeActive = true;

				if (isSelected == selectedItemChanged)
				{
					// Deselecting a single container. This can only happen 
					// when setting IsSelected to false on a specific container. 
					// Note that neither SelectedItem nor CurrentItem are updated 
					// in this case. We only updated the _selectedContainers and 
					// ContainsSelection properties both of which are specific to 
					// the containers in view.
					if (!isSelected && container != null)
					{
						container.IsSelected = false;
						int index = _selectedContainers.IndexOf(container);
						if (index > -1)
						{
							_selectedContainers.RemoveAt(index);
							container.OnUnselected(new RoutedEventArgs(RibbonGalleryItem.UnselectedEvent, container));
						}
					}
					else
					{
						// This is the case where SelectedItem is changing. 
						// We start the processing by deselecting all existing 
						// containers.
						for (int i = 0; i < _selectedContainers.Count; i++)
						{
							RibbonGalleryItem galleryItem = _selectedContainers[i];
							galleryItem.IsSelected = false;
							galleryItem.OnUnselected(new RoutedEventArgs(RibbonGalleryItem.UnselectedEvent, galleryItem));

							if (!isSelected)
							{
								MoveCurrentToPosition(galleryItem.RibbonGalleryCategory.CollectionView, -1);
							}
						}
						_selectedContainers.Clear();

						if (!isSelected)
						{
							SelectedItem = null;
							SelectedValue = null;

							MoveCurrentToPosition(CollectionView, -1);
							MoveCurrentToPosition(SourceCollectionView, -1);
						}
					}

					// Select the item
					if (isSelected)
					{
						SelectedItem = item;
						SelectedValue = GetSelectableValueFromItem(item);

						// Synchronize currency with the specified SelectedItem.
						if (container != null)
						{
							// This is the case where a single container is selected
							SynchronizeWithCurrentItem(container.RibbonGalleryCategory, item);
						}
						else
						{
							// This is the case where the selected item is directly 
							// set in which case we need to additionally find the category 
							// that contains it to perform the currency synchronization
							SynchronizeWithCurrentItem();
						}
					}
				}

				// Select the container and synchronize currency
				if (isSelected && container != null && !_selectedContainers.Contains(container))
				{
					_selectedContainers.Add(container);
					container.IsSelected = true;
					container.OnSelected(new RoutedEventArgs(RibbonGalleryItem.SelectedEvent, container));
				}
			}
			finally
			{
				IsSelectionChangeActive = false;
			}

			if (selectedItemChanged)
			{
				RoutedPropertyChangedEventArgs<object> args = new RoutedPropertyChangedEventArgs<object>(oldItem, isSelected ? newItem : null, SelectionChangedEvent);
				this.OnSelectionChanged(args);
			}
		}

		// To find out if the RibbonGallery contains the specified item. 
		// If ignoreItemContainerGeneratorStatus is true then skip the 
		// container generation check.
		private bool ContainsItem(
			object item,
			bool ignoreItemContainerGeneratorStatus,
			out RibbonGalleryCategory category,
			out RibbonGalleryItem galleryItem)
		{
			category = null;
			galleryItem = null;
			int index = -1;

			if (!ignoreItemContainerGeneratorStatus &&
				ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
			{
				return true;
			}

			foreach (object current in Items)
			{
				category = ItemContainerGenerator.ContainerFromItem(current) as RibbonGalleryCategory;
				if (category != null)
				{
					index = category.Items.IndexOf(item);
					if (index > -1)
					{
						galleryItem = category.ItemContainerGenerator.ContainerFromIndex(index) as RibbonGalleryItem;
						break;
					}
					category = null;
				}
			}

			return index > -1;
		}

		// To find out if the RibbonGallery contains the specified value 
		// in any of the available items. If ignoreItemContainerGeneratorStatus 
		// is true then skip the container generation check.
		private bool ContainsValue(
			object value,
			bool ignoreItemContainerGeneratorStatus,
			out object item,
			out RibbonGalleryCategory category,
			out RibbonGalleryItem galleryItem)
		{
			item = null;
			category = null;
			galleryItem = null;

			if (!ignoreItemContainerGeneratorStatus &&
				ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
			{
				return true;
			}

			ContentControl dummyElement = new ContentControl();

			foreach (object current in Items)
			{
				category = ItemContainerGenerator.ContainerFromItem(current) as RibbonGalleryCategory;
				if (category != null)
				{
					for (int index = 0; index < category.Items.Count; index++)
					{
						item = category.Items[index];
						object itemValue = GetSelectableValueFromItem(item, dummyElement);
						if (VerifyEqual(value, itemValue))
						{
							galleryItem = category.ItemContainerGenerator.ContainerFromIndex(index) as RibbonGalleryItem;
							return true;
						}
						item = null;
					}
					category = null;
				}
			}

			return false;
		}

		internal object GetSelectableValueFromItem(object item)
		{
			return GetSelectableValueFromItem(item, new ContentControl());
		}

		// Find out the value of the item using SelectedValuePath.
		// If there is no SelectedValuePath then item itself is 
		// it's value or the innerText in case of XML node.
		private object GetSelectableValueFromItem(object item, ContentControl dummyElement)
		{
			bool useXml = item is XmlNode;
			Binding itemBinding = new Binding();
			itemBinding.Source = item;
			if (useXml)
			{
				itemBinding.XPath = SelectedValuePath;
				itemBinding.Path = new PropertyPath("/InnerText");
			}
			else
			{
				itemBinding.Path = new PropertyPath(SelectedValuePath);
			}

			// optimize for case where there is no SelectedValuePath (meaning
			// that the value of the item is the item itself, or the InnerText
			// of the item)
			if (string.IsNullOrEmpty(SelectedValuePath))
			{
				// when there's no SelectedValuePath, the binding's Path
				// is either empty (CLR) or "/InnerText" (XML)
				string path = itemBinding.Path.Path;
				Debug.Assert(String.IsNullOrEmpty(path) || path == "/InnerText");
				if (string.IsNullOrEmpty(path))
				{
					// CLR - item is its own selected value
					return item;
				}
				else
				{
					return GetInnerText(item);
				}
			}

			dummyElement.SetBinding(ContentControl.ContentProperty, itemBinding);
			return dummyElement.Content;
		}

		private static object GetInnerText(object item)
		{
			XmlNode node = item as XmlNode;

			if (node != null)
			{
				return node.InnerText;
			}
			else
			{
				return null;
			}
		}

		internal static bool VerifyEqual(object knownValue, object itemValue)
		{
			return Object.Equals(knownValue, itemValue);
		}

		private void MoveCurrentTo(CollectionView cv, object item)
		{
			if (cv != null && IsSynchronizedWithCurrentItemInternal)
			{
				cv.MoveCurrentTo(item);
			}
		}

		private void MoveCurrentToPosition(CollectionView cv, int position)
		{
			if (cv != null && IsSynchronizedWithCurrentItemInternal)
			{
				cv.MoveCurrentToPosition(position);
			}
		}

		internal Collection<RibbonGalleryItem> SelectedContainers
		{
			get { return _selectedContainers; }
		}

		internal RibbonGalleryCategory SelectedCategory
		{
			get
			{
				if (_selectedContainers.Count > 0)
				{
					return _selectedContainers[0].RibbonGalleryCategory;
				}

				return null;
			}

		}

		internal bool IsSelectionChangeActive
		{
			get { return _bits[(int)Bits.IsSelectionChangeActive]; }
			set { _bits[(int)Bits.IsSelectionChangeActive] = value; }
		}

		#endregion Selection

		#region Highlight

		/// <summary>
		///     The DependencyProperty for the <see cref="HighlightedItem"/> property.
		///     Default Value: null
		/// </summary>
		private static readonly DependencyPropertyKey HighlightedItemPropertyKey =
					DependencyProperty.RegisterReadOnly(
										"HighlightedItem",
										typeof(object),
										typeof(RibbonGallery),
										new FrameworkPropertyMetadata(
												new PropertyChangedCallback(OnHighlightedItemChangedPrivate),
												new CoerceValueCallback(CoerceHighlightedItem)));


		/// <summary>
		///     The DependencyProperty for the HighlightedItem property.
		///     Flags:              None
		///     Default Value:      null
		/// </summary>
		public static readonly DependencyProperty HighlightedItemProperty =
				HighlightedItemPropertyKey.DependencyProperty;


		/// <summary>
		///     Specifies the highlighted item.
		/// </summary>
		public object HighlightedItem
		{
			get { return GetValue(HighlightedItemProperty); }
			internal set { SetValue(HighlightedItemPropertyKey, value); }
		}

		// To force Coercion even if the HighlightedItem didn't change, useful in case of when ItemsCollection changes.
		internal void ForceCoerceHighlightedItem()
		{
			try
			{
				ShouldForceCoerceHighlightedItem = true;
				CoerceValue(HighlightedItemProperty);
			}
			finally
			{
				ShouldForceCoerceHighlightedItem = false;
			}
		}

		private static object CoerceHighlightedItem(DependencyObject d, object value)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			if (!gallery.IsHighlightChangeActive)
			{
				object oldItem = gallery.HighlightedItem;
				object newItem = value;

				if (!VerifyEqual(oldItem, newItem))
				{
					if (newItem != null)
					{
						RibbonGalleryCategory category = null;
						RibbonGalleryItem galleryItem = null;

						// If the newItem doesn't exist in RibbonGallery under any category then return UnsetValue
						// so as not to change existing value
						bool ignoreItemContainerGeneratorStatus = false;
						if (!gallery.ContainsItem(newItem, ignoreItemContainerGeneratorStatus, out category, out galleryItem))
						{
							return DependencyProperty.UnsetValue;
						}

						// Changes the highlight to newItem
						gallery.ChangeHighlight(newItem, galleryItem, true);
					}
					else
					{
						// Dehighlight oldItem
						gallery.ChangeHighlight(oldItem, null, false);
					}
				}
				else if (gallery.ShouldForceCoerceHighlightedItem)
				{
					RibbonGalleryCategory category = null;
					RibbonGalleryItem galleryItem = null;

					// This block is called when ItemCollection changes either at the Gallery or the Category levels
					// to handle the case that a previously HighlightedItem is removed or replaced.
					bool ignoreItemContainerGeneratorStatus = true;
					if (!gallery.ContainsItem(newItem, ignoreItemContainerGeneratorStatus, out category, out galleryItem))
					{
						// Dehighlight oldItem
						value = null;
						gallery.ChangeHighlight(oldItem, null, false);
					}
				}
			}

			return value;
		}

		private static void OnHighlightedItemChangedPrivate(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			gallery.OnHighlightedItemChanged(e);
		}

		protected virtual void OnHighlightedItemChanged(DependencyPropertyChangedEventArgs e)
		{
			if (HighlightChanged != null)
			{
				HighlightChanged(this, EventArgs.Empty);
			}

			if (ShouldExecuteCommand && e.OldValue != null)
			{
				CommandHelpers.InvokeCommandSource(CommandParameter, PreviewCommandParameter, this, CommandOperation.CancelPreview);
			}

			if (ShouldExecuteCommand && e.NewValue != null)
			{
				// Fire the Preview operation on a Dispatcher callback to allow the 
				// PreviewCommandParameter's Binding to be updated to match the HighlightedItem
				Dispatcher.BeginInvoke(DispatcherPriority.Send, (DispatcherOperationCallback)delegate(object unused)
				{
					CommandHelpers.InvokeCommandSource(CommandParameter, PreviewCommandParameter, this, CommandOperation.Preview);
					return null;
				}, null);
			}
		}

		// Update all highlighting properties viz. 
		// - HighlightedItem 
		// - IsHighlighted 
		// - HighlightedContainer
		internal void ChangeHighlight(object item, RibbonGalleryItem container, bool isHighlighted)
		{
			if (IsHighlightChangeActive)
			{
				return;
			}

			try
			{
				IsHighlightChangeActive = true;

				if (_highlightedContainer != null)
				{
					_highlightedContainer.IsHighlighted = false;
				}

				if (!isHighlighted)
				{
					_highlightedContainer = null;
					HighlightedItem = null;
				}
				else
				{
					_highlightedContainer = container;
					HighlightedItem = item;

					if (container != null)
					{
						container.IsHighlighted = true;
					}
				}
			}
			finally
			{
				IsHighlightChangeActive = false;
			}
		}

		internal event EventHandler HighlightChanged;

		internal RibbonGalleryCategory HighlightedCategory
		{
			get
			{
				if (_highlightedContainer != null)
				{
					return _highlightedContainer.RibbonGalleryCategory;
				}

				return null;
			}

		}

		internal RibbonGalleryItem HighlightedContainer
		{
			get { return _highlightedContainer; }
		}

		private bool IsHighlightChangeActive
		{
			get { return _bits[(int)Bits.IsHighlightChangeActive]; }
			set { _bits[(int)Bits.IsHighlightChangeActive] = value; }
		}

		private bool ShouldForceCoerceHighlightedItem
		{
			get { return _bits[(int)Bits.ShouldForceCoerceHighlightedItem]; }
			set { _bits[(int)Bits.ShouldForceCoerceHighlightedItem] = value; }
		}

		#endregion Highlight

		#region Filtering

		/// <summary>
		///   Command fired when the user changes the current Gallery filter.
		/// </summary>
		public static RoutedCommand FilterCommand { get; private set; }

		// We only want to execute the FilterCommand if we are in the auto-filtering case and we have filterMenuButton available.
		private static void FilterCanExecute(object sender, CanExecuteRoutedEventArgs args)
		{
			RibbonGallery rg = sender as RibbonGallery;
			if (rg.CanUserFilter &&
				rg._filterMenuButton != null &&
				rg.FilterPaneContent == null &&
				rg.FilterPaneContentTemplate == null)
			{
				args.CanExecute = true;
			}
		}

		private static void FilterExecuted(object sender, ExecutedRoutedEventArgs args)
		{
			RibbonGallery rg = sender as RibbonGallery;
			rg.CurrentFilter = args.Parameter;
			args.Handled = true;
		}

		/// <summary>
		///   Gets/Sets a value indicating whether the Gallery is filterable.
		/// </summary>
		public bool CanUserFilter
		{
			get { return (bool)GetValue(CanUserFilterProperty); }
			set { SetValue(CanUserFilterProperty, value); }
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for CanUserFilter.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty CanUserFilterProperty =
			DependencyProperty.Register("CanUserFilter", typeof(bool), typeof(RibbonGallery), new FrameworkPropertyMetadata(false));

		/// <summary>
		///   Gets/Sets the FilterItemContainerStyle.  This is the container style for the filter items generated from RibbonGalleryCategory Headers.
		/// </summary>
		public Style FilterItemContainerStyle
		{
			get { return (Style)GetValue(FilterItemContainerStyleProperty); }
			set { SetValue(FilterItemContainerStyleProperty, value); }
		}

		/// <summary>
		///   Style to allow customization of the filter items containers.
		/// </summary>
		public static readonly DependencyProperty FilterItemContainerStyleProperty =
			DependencyProperty.Register("FilterItemContainerStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(OnFilterItemContainerStyleChanged));

		/// <summary>
		///   Gets/Sets the AllFilterItemContainerStyle.  This is the container style for the "All" filter.
		/// </summary>
		public Style AllFilterItemContainerStyle
		{
			get { return (Style)GetValue(AllFilterItemContainerStyleProperty); }
			set { SetValue(AllFilterItemContainerStyleProperty, value); }
		}

		/// <summary>
		///   Style to allow customization of the "All" filter item's container.
		/// </summary>
		public static readonly DependencyProperty AllFilterItemContainerStyleProperty =
			DependencyProperty.Register("AllFilterItemContainerStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(OnFilterItemContainerStyleChanged));

		private static void OnFilterItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			// Reapply the FilterItemContainerStyleSelector coercion.
			gallery.CoerceValue(RibbonGallery.FilterItemContainerStyleSelectorProperty);
			gallery.CoerceValue(RibbonGallery.CurrentFilterStyleProperty);
			gallery.SetHeaderBindingForCurrentFilterItem();
		}

		/// <summary>
		///   Gets/Sets the FilterItemContainerStyleSelector.
		/// </summary>
		public StyleSelector FilterItemContainerStyleSelector
		{
			get { return (StyleSelector)GetValue(FilterItemContainerStyleSelectorProperty); }
			set { SetValue(FilterItemContainerStyleSelectorProperty, value); }
		}

		/// <summary>
		///   StyleSelector to allow customization of the filter item containers.
		/// </summary>
		public static readonly DependencyProperty FilterItemContainerStyleSelectorProperty =
			DependencyProperty.Register("FilterItemContainerStyleSelector",
										typeof(StyleSelector),
										typeof(RibbonGallery),
										new FrameworkPropertyMetadata(OnFilterItemContainerStyleSelectorChanged, OnCoerceFilterItemContainerStyleSelector));

		private static void OnFilterItemContainerStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			gallery.CoerceValue(RibbonGallery.CurrentFilterStyleProperty);
			gallery.SetHeaderBindingForCurrentFilterItem();
		}

		// If FilterItemContainerStyle is specified but FilterItemContainerStyleSelector is unspecified, then we supply our own StyleSelector for FilterItemContainerStyleSelector.
		// This allows a user-supplied FilterItemContainerStyle to reskin the filter items without affecting the "All" item.
		//
		// We also coerce when both FilterItemContainerStyle & FilterItemContainerStyleSelector are set so that FilterItemContainerStyle dominates.  Thus, we need to
		// call this coercion whenever the FilterItemContainerStyle property (or AllFilterItemContainerStyle) changes.
		//
		// Similarly, if AllFilterItemContainerStyle is set, the default StyleSelector dominates FilterItemContainerStyleSelector.
		private static object OnCoerceFilterItemContainerStyleSelector(DependencyObject d, object baseValue)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			if (baseValue == null ||
				gallery.FilterItemContainerStyle != null ||
				gallery.AllFilterItemContainerStyle != null)
			{
				return new RibbonGalleryDefaultFilterItemContainerStyleSelector(gallery);
			}

			return baseValue;
		}

		private class RibbonGalleryDefaultFilterItemContainerStyleSelector : StyleSelector
		{
			private RibbonGallery _gallery;

			internal RibbonGalleryDefaultFilterItemContainerStyleSelector(RibbonGallery inputGallery)
				: base()
			{
				_gallery = inputGallery;
			}

			public override Style SelectStyle(object item, DependencyObject container)
			{
				if (Object.ReferenceEquals(item, _allFilter))
				{
					if (_gallery.AllFilterItemContainerStyle != null)
					{
						return _gallery.AllFilterItemContainerStyle;
					}
				}
				else
				{
					if (_gallery.FilterItemContainerStyle != null)
					{
						return _gallery.FilterItemContainerStyle;
					}
				}

				return base.SelectStyle(item, container);
			}
		}

		/// <summary>
		///   Gets/Sets the FilterMenuButtonStyle.
		/// </summary>
		public Style FilterMenuButtonStyle
		{
			get { return (Style)GetValue(FilterMenuButtonStyleProperty); }
			set { SetValue(FilterMenuButtonStyleProperty, value); }
		}

		/// <summary>
		///   Style to allow customization of the Filter menu button.
		/// </summary>
		public static readonly DependencyProperty FilterMenuButtonStyleProperty =
			DependencyProperty.Register("FilterMenuButtonStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(null));

		/// <summary>
		///   Gets/Sets the FilterPaneContent.
		/// </summary>
		public object FilterPaneContent
		{
			get { return (object)GetValue(FilterPaneContentProperty); }
			set { SetValue(FilterPaneContentProperty, value); }
		}

		/// <summary>
		///   Object to allow customization of the Filter pane.
		/// </summary>
		public static readonly DependencyProperty FilterPaneContentProperty =
			DependencyProperty.Register("FilterPaneContent", typeof(object), typeof(RibbonGallery), new FrameworkPropertyMetadata(null));

		/// <summary>
		///   Gets/Sets the FilterPaneContentTemplate.
		/// </summary>
		public DataTemplate FilterPaneContentTemplate
		{
			get { return (DataTemplate)GetValue(FilterPaneContentTemplateProperty); }
			set { SetValue(FilterPaneContentTemplateProperty, value); }
		}

		/// <summary>
		///   DataTemplate to allow customization of the Filter pane.
		/// </summary>
		public static readonly DependencyProperty FilterPaneContentTemplateProperty =
			DependencyProperty.Register("FilterPaneContentTemplate", typeof(DataTemplate), typeof(RibbonGallery), new FrameworkPropertyMetadata(null));

		/// <summary>
		///   Gets/Sets the FilterItemTemplate.  This specifies the template for filter items generated from RibbonGalleryCategory Headers.
		/// </summary>
		public DataTemplate FilterItemTemplate
		{
			get { return (DataTemplate)GetValue(FilterItemTemplateProperty); }
			set { SetValue(FilterItemTemplateProperty, value); }
		}

		/// <summary>
		///   DataTemplate to allow customization of the filter items.
		/// </summary>
		public static readonly DependencyProperty FilterItemTemplateProperty =
			DependencyProperty.Register("FilterItemTemplate", typeof(DataTemplate), typeof(RibbonGallery), new FrameworkPropertyMetadata(OnFilterItemTemplateChanged));

		/// <summary>
		///   Gets/Sets the AllFilterItemTemplate.  This specifies the template for the "All" filter item.
		/// </summary>
		public DataTemplate AllFilterItemTemplate
		{
			get { return (DataTemplate)GetValue(AllFilterItemTemplateProperty); }
			set { SetValue(AllFilterItemTemplateProperty, value); }
		}

		/// <summary>
		///   DataTemplate to allow customization of the "All" filter item.
		/// </summary>
		public static readonly DependencyProperty AllFilterItemTemplateProperty =
			DependencyProperty.Register("AllFilterItemTemplate", typeof(DataTemplate), typeof(RibbonGallery), new FrameworkPropertyMetadata(OnFilterItemTemplateChanged));

		private static void OnFilterItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			// Reapply the FilterItemTemplateSelector coercion.
			gallery.CoerceValue(RibbonGallery.FilterItemTemplateSelectorProperty);
			gallery.CoerceValue(RibbonGallery.CurrentFilterTemplateProperty);
		}

		/// <summary>
		///   Gets/Sets the FilterItemTemplateSelector.
		/// </summary>
		public DataTemplateSelector FilterItemTemplateSelector
		{
			get { return (DataTemplateSelector)GetValue(FilterItemTemplateSelectorProperty); }
			set { SetValue(FilterItemTemplateSelectorProperty, value); }
		}

		/// <summary>
		///   DataTemplateSelector to allow customization of the filter items.
		/// </summary>
		public static readonly DependencyProperty FilterItemTemplateSelectorProperty =
			DependencyProperty.Register("FilterItemTemplateSelector",
										typeof(DataTemplateSelector),
										typeof(RibbonGallery),
										new FrameworkPropertyMetadata(OnFilterItemTemplateSelectorChanged, OnCoerceFilterItemTemplateSelector));

		private static void OnFilterItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			gallery.CoerceValue(RibbonGallery.CurrentFilterTemplateProperty);
		}

		// If FilterItemTemplate is specified but FilterItemTemplateSelector is unspecified, then we supply our own DataTemplateSelector for FilterItemTemplateSelector.
		// This allows a user-supplied FilterItemTemplate to reskin the filter items without affecting the "All" item.
		//
		// We also coerce when both FilterItemTemplate & FilterItemTemplateSelector are set so that FilterItemTemplate dominates.  Thus, we need to
		// call this coercion whenever the FilterItemTemplate (or AllFilterItemTemplate) property changes.
		//
		// Similarly, if AllFilterItemTemplate is set, then the default DataTemplateSelector dominates FilterItemTemplateSelector.
		private static object OnCoerceFilterItemTemplateSelector(DependencyObject d, object baseValue)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			if (baseValue == null ||
				gallery.FilterItemTemplate != null ||
				gallery.AllFilterItemTemplate != null)
			{
				return new RibbonGalleryDefaultFilterItemTemplateSelector(gallery);
			}

			return baseValue;
		}

		private class RibbonGalleryDefaultFilterItemTemplateSelector : DataTemplateSelector
		{
			private RibbonGallery _gallery;

			internal RibbonGalleryDefaultFilterItemTemplateSelector(RibbonGallery inputGallery)
				: base()
			{
				_gallery = inputGallery;
			}

			public override DataTemplate SelectTemplate(object item, DependencyObject container)
			{
				if (Object.ReferenceEquals(item, _allFilter))
				{
					if (_gallery.AllFilterItemTemplate != null)
					{
						return _gallery.AllFilterItemTemplate;
					}
				}
				else
				{
					if (_gallery.FilterItemTemplate != null)
					{
						return _gallery.FilterItemTemplate;
					}
				}

				return base.SelectTemplate(item, container);
			}
		}

		internal ContentPresenter FilterContentPane
		{
			get
			{
				return _filterContentPane;
			}
		}

		internal RibbonMenuButton FilterMenuButton
		{
			get
			{
				return _filterMenuButton;
			}
		}

		#endregion Filtering

		#region ContainerGeneration

		protected override bool IsItemItsOwnContainerOverride(object item)
		{
			return item is RibbonGalleryCategory;
		}

		protected override DependencyObject GetContainerForItemOverride()
		{
			return new RibbonGalleryCategory();
		}

		/// <summary>
		///   Called when the container is being attached to the parent ItemsControl
		/// </summary>
		/// <param name="element"></param>
		/// <param name="item"></param>
		protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
		{
			RibbonGalleryCategory category = (RibbonGalleryCategory)element;
			category.RibbonGallery = this;

			if (SelectedValue != null && SelectedItem == null)
			{
				// Synchronize SelectedItem with SelectedValue
				ForceCoerceSelectedValue();
			}

			if (HasItems)
			{
				object selectedItem = SelectedItem;
				for (int index = 0; index < category.Items.Count; index++)
				{
					RibbonGalleryItem galleryItem = category.ItemContainerGenerator.ContainerFromIndex(index) as RibbonGalleryItem;
					if (galleryItem != null)
					{
						// Set IsSelected to true on GalleryItems that match the SelectedItem
						if (selectedItem != null)
						{
							if (VerifyEqual(selectedItem, category.Items[index]))
							{
								galleryItem.IsSelected = true;
							}
						}
						else if (galleryItem.IsSelected)
						{
							// If a GalleryItem is marked IsSelected true then synchronize SelectedItem with it
							SelectedItem = category.Items[index];
						}
					}
				}
			}

			// copy templates and styles from this ItemsControl
			var itemTemplate = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemTemplateProperty);
			var itemTemplateSelector = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemTemplateSelectorProperty);
			var itemStringFormat = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemStringFormatProperty);
			var itemContainerStyle = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemContainerStyleProperty);
			var itemContainerStyleSelector = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemContainerStyleSelectorProperty);
			var alternationCount = RibbonHelper.GetValueAndValueSource(category, ItemsControl.AlternationCountProperty);
			var itemBindingGroup = RibbonHelper.GetValueAndValueSource(category, ItemsControl.ItemBindingGroupProperty);

			base.PrepareContainerForItemOverride(element, item);

			// Call this function to work around a restriction of supporting hetrogenous 
			// ItemsCotnrol hierarchy. The method takes care of both ItemsControl and
			// HeaderedItemsControl (in this case) and assign back the default properties
			// whereever appropriate.
			RibbonHelper.IgnoreDPInheritedFromParentItemsControl(
				category,
				this,
				itemTemplate,
				itemTemplateSelector,
				itemStringFormat,
				itemContainerStyle,
				itemContainerStyleSelector,
				alternationCount,
				itemBindingGroup,
				null,
				null,
				null);
		}

		/// <summary>
		///   Called when the container is being detached from the parent ItemsControl
		/// </summary>
		/// <param name="element"></param>
		/// <param name="item"></param>
		protected override void ClearContainerForItemOverride(DependencyObject element, object item)
		{
			RibbonGalleryCategory category = (RibbonGalleryCategory)element;

			for (int index = 0; index < category.Items.Count; index++)
			{
				RibbonGalleryItem galleryItem = category.ItemContainerGenerator.ContainerFromIndex(index) as RibbonGalleryItem;
				if (galleryItem != null)
				{
					object dataItem = category.Items[index];

					// Turn off selection and highlight on GalleryItems that are being cleared. 
					// Note that we directly call Change[Selection/Highlight] instead of setting 
					// Is[Selected/Highlighted] because we aren't able to get ItemFromContainer 
					// in OnIs[Selected/Highlighted]Changed because the ItemContainerGenerator 
					// has already detached this container. 
					if (galleryItem.IsHighlighted)
					{
						galleryItem.RibbonGallery.ChangeHighlight(dataItem, galleryItem, false);
					}
					if (galleryItem.IsSelected)
					{
						galleryItem.RibbonGallery.ChangeSelection(dataItem, galleryItem, false);
					}
				}
			}

			category.RibbonGallery = null;
			base.ClearContainerForItemOverride(element, item);
		}

		#endregion ContainerGeneration

		#region DropDownContainer

		/// <summary>
		///     True if this is the current "Selection" of its parent.
		///     A gallery is selected when Keyboard focus is within or mouse enters.
		/// </summary>
		internal bool IsSelected
		{
			get { return (bool)GetValue(IsSelectedProperty); }
			set { SetValue(IsSelectedProperty, value); }
		}

		/// <summary>
		///     DependencyProperty for IsSelected property.
		/// </summary>
		internal static readonly DependencyProperty IsSelectedProperty = RibbonMenuItem.IsSelectedProperty.AddOwner(typeof(RibbonGallery),
																													new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsSelectedChanged)));

		private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			((RibbonGallery)d).RaiseEvent(new RoutedPropertyChangedEventArgs<bool>((bool)e.OldValue, (bool)e.NewValue, RibbonMenuButton.IsSelectedChangedEvent));
		}

		/// <summary>
		/// Called when the focus changes within the subtree
		/// </summary>
		protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
		{
			base.OnIsKeyboardFocusWithinChanged(e);

			if (IsKeyboardFocusWithin && !IsSelected)
			{
				// If an item within us got focus (probably programatically), we need to become selected
				IsSelected = true;
			}
		}

		#endregion

		#region CollectionChange

		private void RepopulateCategoryFilters()
		{
			_categoryFilters.Clear();

			// Add the "All" filter and make this the current filter.
			_categoryFilters.Add(_allFilter);

			// Search Items collection for categories.
			for (int i = 0; i < this.Items.Count; i++)
			{
				RibbonGalleryCategory category;
				object filterToAdd;

				// If this item is a RibbonGalleryCategory, then add its Header to the filters collection.
				// Otherwise add the item itself.
				if (this.Items[i] is RibbonGalleryCategory)
				{
					category = (RibbonGalleryCategory)this.Items[i];
					filterToAdd = category.Header;
				}
				else
				{
					category = (RibbonGalleryCategory)this.ItemContainerGenerator.ContainerFromIndex(i);
					filterToAdd = this.Items[i];
				}

				// RibbonGalleryCategories that omit Header are omitted from the filters collection.
				// If category.Header is a string, make sure it is non-empty as well.
				if ((category.Header is string && !String.IsNullOrEmpty((string)category.Header)) ||
					 category.Header != null)
				{
					_categoryFilters.Add(filterToAdd);
				}
			}

			CurrentFilter = _allFilter;
		}

		private static void OnCurrentFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			object newFilter = e.NewValue;

			Debug.Assert(gallery.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated);

			for (int i = 0; i < gallery.Items.Count; i++)
			{
				RibbonGalleryCategory category;
				object dataToCompareAgainst;

				// If this item is a RibbonGalleryCategory, then we want to compare against its Header.
				// Otherwise compare against the item itself.
				if (gallery.Items[i] is RibbonGalleryCategory)
				{
					category = (RibbonGalleryCategory)gallery.Items[i];
					dataToCompareAgainst = category.Header;
				}
				else
				{
					category = (RibbonGalleryCategory)gallery.ItemContainerGenerator.ContainerFromIndex(i);
					dataToCompareAgainst = gallery.Items[i];
				}

				// Show the category if the current filter is the "All" filter or dataToCompareAgainst.
				if (Object.ReferenceEquals(newFilter, _allFilter) ||
					Object.ReferenceEquals(newFilter, dataToCompareAgainst))
				{
					category.Visibility = Visibility.Visible;
				}
				else
				{
					category.Visibility = Visibility.Collapsed;
				}
			}

			gallery.CoerceValue(RibbonGallery.CurrentFilterStyleProperty);
			gallery.SetHeaderBindingForCurrentFilterItem();
			gallery.CoerceValue(RibbonGallery.CurrentFilterTemplateProperty);
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for CurrentFilter.  This enables animation, styling, binding, etc...
		/// </summary>
		private static readonly DependencyProperty CurrentFilterProperty =
			DependencyProperty.Register("CurrentFilter", typeof(object), typeof(RibbonGallery), new FrameworkPropertyMetadata(_allFilter, OnCurrentFilterChanged));

		/// <summary>
		///   Specifies the current filter.
		/// </summary>
		private object CurrentFilter
		{
			get { return GetValue(CurrentFilterProperty); }
			set { SetValue(CurrentFilterProperty, value); }
		}

		/// <summary>
		///   The "All" item in a RibbonGallery filter.  This is a localized string.
		///   
		///   Custom FilterItemTemplateSelector or FilterItemContainerStyleSelector implementations can use this to
		///   distinguish between the "All" filter item and normal filter items.
		/// </summary>
		public static object AllFilterItem
		{
			get { return _allFilter; }
		}

		/// <summary>
		///   This method is invoked when the Items property changes.
		/// </summary>
		protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
		{
			switch (e.Action)
			{
				case NotifyCollectionChangedAction.Remove:
				case NotifyCollectionChangedAction.Reset:
				case NotifyCollectionChangedAction.Replace:
					if (SelectedItem != null)
					{
						// Synchronize SelectedItem after Remove, Replace or Reset operations.
						ForceCoerceSelectedItem();
					}
					if (HighlightedItem != null)
					{
						// Synchronize HighlightedItem after Remove, Replace or Reset operations.
						ForceCoerceHighlightedItem();
					}
					break;

				case NotifyCollectionChangedAction.Add:
				case NotifyCollectionChangedAction.Move:
					break;
			}
		}

		#endregion CollectionChange

		#region CategoryTemplate

		/// <summary>
		///     Equivalent of ItemTemplate.
		/// </summary>
		/// <remarks>
		///     If this property has a non-null value, it will override the value
		///     of ItemTemplate.
		/// </remarks>
		[BindableAttribute(true)]
		public DataTemplate CategoryTemplate
		{
			get { return (DataTemplate)GetValue(CategoryTemplateProperty); }
			set { SetValue(CategoryTemplateProperty, value); }
		}

		/// <summary>
		///     DependencyProperty for the CategoryStyle property.
		/// </summary>
		public static readonly DependencyProperty CategoryTemplateProperty =
			DependencyProperty.Register("CategoryTemplate", typeof(DataTemplate), typeof(RibbonGallery), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnCategoryTemplateChanged)));

		private static void OnCategoryTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			d.CoerceValue(ItemTemplateProperty);
		}

		// Always respect CategoryTemplate property over ItemTemplateProperty
		private static object OnCoerceItemTemplate(DependencyObject d, object baseValue)
		{
			if (!PropertyHelper.IsDefaultValue(d, RibbonGallery.CategoryTemplateProperty))
			{
				return d.GetValue(RibbonGallery.CategoryTemplateProperty);
			}

			return baseValue;
		}

		/// <summary>
		///     Equivalent of ItemContainerStyle.
		/// </summary>
		/// <remarks>
		///     If this property has a non-null value, it will override the value
		///     of ItemContainerStyle.
		/// </remarks>
		public Style CategoryStyle
		{
			get { return (Style)GetValue(CategoryStyleProperty); }
			set { SetValue(CategoryStyleProperty, value); }
		}

		/// <summary>
		///     DependencyProperty for the CategoryStyle property.
		/// </summary>
		public static readonly DependencyProperty CategoryStyleProperty =
			DependencyProperty.Register("CategoryStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnCategoryStyleChanged)));

		private static void OnCategoryStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			d.CoerceValue(ItemContainerStyleProperty);
		}

		// // Always respect CategoryStyleProperty property over ItemConatinerStyleProperty
		private static object OnCoerceItemContainerStyle(DependencyObject d, object baseValue)
		{
			if (!PropertyHelper.IsDefaultValue(d, RibbonGallery.CategoryStyleProperty))
			{
				return d.GetValue(RibbonGallery.CategoryStyleProperty);
			}

			return baseValue;
		}

		#endregion CategoryTemplate

		#region GalleryItemTemplate

		public DataTemplate GalleryItemTemplate
		{
			get { return (DataTemplate)GetValue(GalleryItemTemplateProperty); }
			set { SetValue(GalleryItemTemplateProperty, value); }
		}

		public static readonly DependencyProperty GalleryItemTemplateProperty =
			DependencyProperty.Register("GalleryItemTemplate", typeof(DataTemplate), typeof(RibbonGallery), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnNotifyGalleryItemTemplateOrStylePropertyChanged)));

		public Style GalleryItemStyle
		{
			get { return (Style)GetValue(GalleryItemStyleProperty); }
			set { SetValue(GalleryItemStyleProperty, value); }
		}

		public static readonly DependencyProperty GalleryItemStyleProperty =
						DependencyProperty.Register("GalleryItemStyle", typeof(Style), typeof(RibbonGallery), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnNotifyGalleryItemTemplateOrStylePropertyChanged)));

		private static void OnNotifyGalleryItemTemplateOrStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;

			for (int index = 0; index < gallery.Items.Count; index++)
			{
				RibbonGalleryCategory category = (RibbonGalleryCategory)gallery.ItemContainerGenerator.ContainerFromIndex(index);

				if (category != null)
				{
					category.NotifyPropertyChanged(e);
				}
			}
		}

		#endregion GalleryItemTemplate

		#region Automation

		protected override AutomationPeer OnCreateAutomationPeer()
		{
			return new RibbonGalleryAutomationPeer(this);
		}

		#endregion Automation

		#region Input Handling

		// The RibbonGallery tracks the position of the mouse relative to
		// itself in order to differentiate cases where the mouse move event
		// is generated as an artifact of elements moving (eg. scrolling) vs
		// the mouse actually moving.  We track this point by listening to the
		// MouseEnter/MouseMove/MouseLeave events.  The pattern is for
		// RibbonGalleryItems to call DidMouseMove in response to the bubbling
		// MouseMove event, which should be routed through the
		// RibbonGalleryItems before it is routed through the RibbonGallery.

		protected override void OnMouseEnter(MouseEventArgs e)
		{
			_localMousePosition = e.GetPosition(this);
			if (!IsSelected)
			{
				// If it's already focused, make sure it's also selected.
				IsSelected = true;
			}

			base.OnMouseEnter(e);
		}

		protected override void OnMouseLeave(MouseEventArgs e)
		{
			_localMousePosition = null;
			if (IsSelected)
			{
				IsSelected = false;
			}
			base.OnMouseLeave(e);
		}

		private static void OnMouseMove(object sender, MouseEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)sender;
			gallery._localMousePosition = e.GetPosition(gallery);
		}

		internal bool DidMouseMove(MouseEventArgs e)
		{
			//Debug.Assert(e.RoutedEvent == Mouse.MouseMoveEvent || e.RoutedEvent == Mouse.MouseLeaveEvent);
			//Debug.Assert(_localMousePosition.HasValue);

			if ((e.RoutedEvent == Mouse.MouseMoveEvent || e.RoutedEvent == Mouse.MouseLeaveEvent)
				&& _localMousePosition.HasValue)
			{
				Point currentMousePosition = e.GetPosition(this);
				return currentMousePosition != _localMousePosition;
			}

			return false;
		}

		private Point? _localMousePosition;

		/// <summary>
		/// Gallery's ScrollViewer handles up/down arrow keys and marks the KeyDown event handled
		/// even if the next focusable element is not its descendant.
		/// The logic here enables navigation to outside the gallery 
		/// (for e.g. from the last/first galleryItem to gallery's sibling MenuItem).
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPreviewKeyDown(KeyEventArgs e)
		{
			base.OnPreviewKeyDown(e);

			if (!e.Handled)
			{
				DependencyObject focusedElement = Keyboard.FocusedElement as DependencyObject;
				OnNavigationKeyDown(e, focusedElement);
			}
		}

		internal void OnNavigationKeyDown(KeyEventArgs e, DependencyObject focusedElement)
		{
			if (e.Key == Key.Down || e.Key == Key.Up)
			{
				FocusNavigationDirection direction = (e.Key == Key.Down) ? FocusNavigationDirection.Down : FocusNavigationDirection.Up;
				DependencyObject predictedFocus = null;

				if (focusedElement != null)
				{
					// if predictedFocus is not a descendant of the Gallery._scrollViewer
					// then handle the navigation
					predictedFocus = RibbonHelper.PredictFocus(focusedElement, direction) as UIElement;
					if (_scrollViewer != null && predictedFocus != null)
					{
						ScrollViewer predictedFocusAncestor = TreeHelper.FindVisualAncestor<ScrollViewer>(predictedFocus);
						if (predictedFocusAncestor != _scrollViewer)
						{
							RibbonHelper.Focus(predictedFocus);
							e.Handled = true;
						}
					}
				}
			}
			else if ((e.Key == Key.Left) == (FlowDirection == FlowDirection.LeftToRight))
			{
				UIElement predictedFocus = null;
				FocusNavigationDirection direction = (FlowDirection == FlowDirection.LeftToRight ? FocusNavigationDirection.Left : FocusNavigationDirection.Right);
				if (focusedElement != null)
				{
					RibbonMenuItem menuItem = TreeHelper.FindAncestor(this, delegate(DependencyObject d) { return (d is RibbonMenuItem); }) as RibbonMenuItem;
					if (menuItem != null)
					{
						predictedFocus = RibbonHelper.PredictFocus(focusedElement, direction) as UIElement;
						bool callRibbonMenuItemHandler = false;

						// If predicted focus of logical left is null or the focused element
						// itself or if its origin with respect to screen is logically to the
						// right of focused element, then assume that we are at the left boundary 
						// (any maybe trying to cycle) and hence make the
						// ancestor RibbonMenuItem handle the event.
						if (predictedFocus == null ||
							predictedFocus == focusedElement)
						{
							callRibbonMenuItemHandler = true;
						}
						else
						{
							Point focusedOrigin = new Point();
							UIElement focusContainer = RibbonHelper.GetContainingUIElement(focusedElement);
							if (focusContainer != null)
							{
								focusedOrigin = focusContainer.PointToScreen(new Point());
							}
							Point predictedFocusedOrigin = predictedFocus.PointToScreen(new Point());
							if ((FlowDirection == FlowDirection.LeftToRight && DoubleUtil.GreaterThan(predictedFocusedOrigin.X, focusedOrigin.X)) ||
								(FlowDirection == FlowDirection.RightToLeft && DoubleUtil.LessThan(predictedFocusedOrigin.X, focusedOrigin.X)))
							{
								callRibbonMenuItemHandler = true;
							}
						}

						if (callRibbonMenuItemHandler)
						{
							e.Handled = menuItem.HandleLeftKeyDown(e.OriginalSource as DependencyObject);
						}
					}
				}
			}
			else if (e.Key == Key.PageDown || e.Key == Key.PageUp)
			{
				FocusNavigationDirection direction = e.Key == Key.PageDown ? FocusNavigationDirection.Down : FocusNavigationDirection.Up;

				RibbonGalleryItem focusedGalleryItem = focusedElement as RibbonGalleryItem;
				if (focusedGalleryItem != null)
				{
					RibbonGalleryItem highlightedGalleryItem;
					e.Handled = RibbonHelper.NavigatePageAndHighlightRibbonGalleryItem(
						this,
						focusedGalleryItem,
						direction,
						out highlightedGalleryItem);

					if (highlightedGalleryItem != null)
					{
						highlightedGalleryItem.Focus();
						highlightedGalleryItem.BringIntoView();
					}
				}
			}
		}

		private static void OnDismissPopupThunk(object sender, RibbonDismissPopupEventArgs e)
		{
			RibbonGallery ribbonGallery = (RibbonGallery)sender;
			ribbonGallery.OnDismissPopup(e);
		}

		private void OnDismissPopup(RibbonDismissPopupEventArgs e)
		{
			if (e.DismissMode == RibbonDismissPopupMode.Always)
			{
				// Stop popup dismissal if the original source
				// is from FilterPane.
				ContentPresenter filterPane = FilterContentPane;
				if (filterPane != null &&
					RibbonHelper.IsAncestorOf(filterPane, e.OriginalSource as DependencyObject))
				{
					e.Handled = true;
				}
			}
		}

		#endregion Input Handling

		#region Commanding

		/// <summary>
		///   Gets or sets the Command that will be executed when the command source is invoked.
		/// </summary>
		public ICommand Command
		{
			get { return (ICommand)GetValue(CommandProperty); }
			set { SetValue(CommandProperty, value); }
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for CommandProperty.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty CommandProperty =
					DependencyProperty.Register(
							"Command",
							typeof(ICommand),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));

		/// <summary>
		///   Gets or sets a user defined data value that can be passed to the command when it is executed.
		/// </summary>
		public object CommandParameter
		{
			get { return (object)GetValue(CommandParameterProperty); }
			set { SetValue(CommandParameterProperty, value); }
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for CommandParameterProperty.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty CommandParameterProperty =
					DependencyProperty.Register(
							"CommandParameter",
							typeof(object),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(null));

		/// <summary>
		///   Gets or sets a user defined data value that can be passed to the command when it is previewed.
		/// </summary>
		public object PreviewCommandParameter
		{
			get { return (object)GetValue(PreviewCommandParameterProperty); }
			set { SetValue(PreviewCommandParameterProperty, value); }
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for PreviewCommandParameterProperty.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty PreviewCommandParameterProperty =
					DependencyProperty.Register(
							"PreviewCommandParameter",
							typeof(object),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(null));

		/// <summary>
		///   Gets or sets the object that the command is being executed on.
		/// </summary>
		public IInputElement CommandTarget
		{
			get { return (IInputElement)GetValue(CommandTargetProperty); }
			set { SetValue(CommandTargetProperty, value); }
		}

		/// <summary>
		///   Using a DependencyProperty as the backing store for CommandTargetProperty.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty CommandTargetProperty =
					DependencyProperty.Register(
							"CommandTarget",
							typeof(IInputElement),
							typeof(RibbonGallery),
							new FrameworkPropertyMetadata(null));

		private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)d;
			ICommand oldCommand = (ICommand)e.OldValue;
			ICommand newCommand = (ICommand)e.NewValue;

			if (oldCommand != null)
			{
				gallery.UnhookCommand(oldCommand);
			}
			if (newCommand != null)
			{
				gallery.HookCommand(newCommand);
			}

			RibbonHelper.OnCommandChanged(d, e);
		}

		private void HookCommand(ICommand command)
		{
			_canExecuteChangedHandler = new EventHandler(OnCanExecuteChanged);
			command.CanExecuteChanged += _canExecuteChangedHandler;
			UpdateCanExecute();
		}

		private void UnhookCommand(ICommand command)
		{
			if (_canExecuteChangedHandler != null)
			{
				command.CanExecuteChanged -= _canExecuteChangedHandler;
				_canExecuteChangedHandler = null;
			}
			UpdateCanExecute();
		}

		private void OnCanExecuteChanged(object sender, EventArgs e)
		{
			UpdateCanExecute();
		}

		private void UpdateCanExecute()
		{
			if (Command != null)
			{
				CanExecute = CommandHelpers.CanExecuteCommandSource(CommandParameter, this);
			}
			else
			{
				CanExecute = true;
			}
		}

		/// <summary>
		///     Fetches the value of the IsEnabled property
		/// </summary>
		/// <remarks>
		///     The reason this property is overridden is so that RibbonGallery
		///     can infuse the value for CanExecute into it.
		/// </remarks>
		protected override bool IsEnabledCore
		{
			get
			{
				return base.IsEnabledCore && CanExecute;
			}
		}

		private bool CanExecute
		{
			get { return _bits[(int)Bits.CanExecute]; ; }
			set
			{
				_bits[(int)Bits.CanExecute] = value;
				CoerceValue(IsEnabledProperty);
			}
		}

		private EventHandler _canExecuteChangedHandler;

		#endregion Commanding

		#region RibbonControlService Properties

		/// <summary>
		///     DependencyProperty for SmallImageSource property.
		/// </summary>
		public static readonly DependencyProperty SmallImageSourceProperty =
			RibbonControlService.SmallImageSourceProperty.AddOwner(typeof(RibbonGallery));

		/// <summary>
		///     ImageSource property which is normally a 16X16 icon.
		/// </summary>
		public ImageSource SmallImageSource
		{
			get { return RibbonControlService.GetSmallImageSource(this); }
			set { RibbonControlService.SetSmallImageSource(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipTitle property.
		/// </summary>
		public static readonly DependencyProperty ToolTipTitleProperty =
			RibbonControlService.ToolTipTitleProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Title text for the tooltip of the control.
		/// </summary>
		public string ToolTipTitle
		{
			get { return RibbonControlService.GetToolTipTitle(this); }
			set { RibbonControlService.SetToolTipTitle(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipDescription property.
		/// </summary>
		public static readonly DependencyProperty ToolTipDescriptionProperty =
			RibbonControlService.ToolTipDescriptionProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Description text for the tooltip of the control.
		/// </summary>
		public string ToolTipDescription
		{
			get { return RibbonControlService.GetToolTipDescription(this); }
			set { RibbonControlService.SetToolTipDescription(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipImageSource property.
		/// </summary>
		public static readonly DependencyProperty ToolTipImageSourceProperty =
			RibbonControlService.ToolTipImageSourceProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Image source for the tooltip of the control.
		/// </summary>
		public ImageSource ToolTipImageSource
		{
			get { return RibbonControlService.GetToolTipImageSource(this); }
			set { RibbonControlService.SetToolTipImageSource(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipFooterTitle property.
		/// </summary>
		public static readonly DependencyProperty ToolTipFooterTitleProperty =
			RibbonControlService.ToolTipFooterTitleProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Title text for the footer of tooltip of the control.
		/// </summary>
		public string ToolTipFooterTitle
		{
			get { return RibbonControlService.GetToolTipFooterTitle(this); }
			set { RibbonControlService.SetToolTipFooterTitle(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipFooterDescription property.
		/// </summary>
		public static readonly DependencyProperty ToolTipFooterDescriptionProperty =
			RibbonControlService.ToolTipFooterDescriptionProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Description text for the footer of the tooltip of the control.
		/// </summary>
		public string ToolTipFooterDescription
		{
			get { return RibbonControlService.GetToolTipFooterDescription(this); }
			set { RibbonControlService.SetToolTipFooterDescription(this, value); }
		}

		/// <summary>
		///     DependencyProperty for ToolTipFooterImageSource property.
		/// </summary>
		public static readonly DependencyProperty ToolTipFooterImageSourceProperty =
			RibbonControlService.ToolTipFooterImageSourceProperty.AddOwner(typeof(RibbonGallery), new FrameworkPropertyMetadata(new PropertyChangedCallback(RibbonHelper.OnRibbonToolTipPropertyChanged)));

		/// <summary>
		///     Image source for the footer of the tooltip of the control.
		/// </summary>
		public ImageSource ToolTipFooterImageSource
		{
			get { return RibbonControlService.GetToolTipFooterImageSource(this); }
			set { RibbonControlService.SetToolTipFooterImageSource(this, value); }
		}

		/// <summary>
		///     DependencyProperty for Ribbon property.
		/// </summary>
		public static readonly DependencyProperty RibbonProperty =
			RibbonControlService.RibbonProperty.AddOwner(typeof(RibbonGallery));

		/// <summary>
		///     This property is used to access visual style brushes defined on the Ribbon class.
		/// </summary>
		public Ribbon Ribbon
		{
			get { return RibbonControlService.GetRibbon(this); }
		}

		#endregion RibbonControlService Properties

		#region Scrolling

		/// <summary>
		///  This method allows a particular item to be scrolled into view
		/// </summary>
		/// <remarks>
		///   Note that this method currently does not support the virtualization
		/// </remarks>
		/// <param name="item"></param>
		public void ScrollIntoView(object item)
		{
			if (item != null)
			{
				// This is a fast path to scroll to the selected or the highlighted item

				if (VerifyEqual(item, SelectedItem) && _selectedContainers.Count > 0)
				{
					_selectedContainers[0].BringIntoView();
				}
				else if (VerifyEqual(item, HighlightedItem) && _highlightedContainer != null)
				{
					_highlightedContainer.BringIntoView();
				}
				else
				{
					// If this a request for an arbitrary item then we need to 
					// find its container and then scroll that into view.

					RibbonGalleryCategory category = null;
					RibbonGalleryItem galleryItem = null;

					bool ignoreItemContainerGeneratorStatus = true;
					if (ContainsItem(item, ignoreItemContainerGeneratorStatus, out category, out galleryItem) &&
						galleryItem != null)
					{
						galleryItem.BringIntoView();
					}
				}
			}
		}

		private static void OnLoaded(object sender, RoutedEventArgs e)
		{
			// A RibbonGallery is always hosted within a drop down control 
			// viz. RibbonMenuButton, RibbonComboBox, RibbonMenuItem, etc.
			// In all of these cases we wish to scroll the selected item 
			// into view when the drop down first opens. Hence this clause 
			// in RibbonGallery.

			RibbonGallery gallery = (RibbonGallery)sender;
			gallery.ScrollIntoView(gallery.SelectedItem);
		}

		private static void OnUnloaded(object sender, RoutedEventArgs e)
		{
			RibbonGallery gallery = (RibbonGallery)sender;

			// Invalidate these layout calculations, so that these are recalculated when drop down is opened. 
			// We would need invalidation if any Items are removed from the parent RibbonMenuButton causing its constraint to change. 
			gallery.IsArrangeWidthValid = false;
			gallery.IsMaxColumnWidthValid = false;
		}

		internal bool ShouldGalleryItemsAcquireFocus
		{
			get { return _bits[(int)Bits.ShouldGalleryItemsAcquireFocus]; }
			set { _bits[(int)Bits.ShouldGalleryItemsAcquireFocus] = value; }
		}

		internal bool HasHighlightChangedViaMouse
		{
			get { return _bits[(int)Bits.HighlightChangedViaMouse]; }
			set { _bits[(int)Bits.HighlightChangedViaMouse] = value; }
		}

		#endregion Scrolling

		#region QAT

		/// <summary>
		///   DependencyProperty for QuickAccessToolBarId property.
		/// </summary>
		public static readonly DependencyProperty QuickAccessToolBarIdProperty =
			RibbonControlService.QuickAccessToolBarIdProperty.AddOwner(typeof(RibbonGallery));

		/// <summary>
		///   This property is used as a unique identifier to link a control in the Ribbon with its counterpart in the QAT.
		/// </summary>
		public object QuickAccessToolBarId
		{
			get { return RibbonControlService.GetQuickAccessToolBarId(this); }
			set { RibbonControlService.SetQuickAccessToolBarId(this, value); }
		}

		/// <summary>
		///   DependencyProperty for CanAddToQuickAccessToolBarDirectly property.
		/// </summary>
		public static readonly DependencyProperty CanAddToQuickAccessToolBarDirectlyProperty =
			RibbonControlService.CanAddToQuickAccessToolBarDirectlyProperty.AddOwner(typeof(RibbonGallery),
			new FrameworkPropertyMetadata(true));


		/// <summary>
		///   Property determining whether a control can be added to the RibbonQuickAccessToolBar directly.
		/// </summary>
		public bool CanAddToQuickAccessToolBarDirectly
		{
			get { return RibbonControlService.GetCanAddToQuickAccessToolBarDirectly(this); }
			set { RibbonControlService.SetCanAddToQuickAccessToolBarDirectly(this, value); }
		}

		#endregion QAT

		#region Data

		private enum Bits
		{
			IsSelectionChangeActive = 0x1,
			IsHighlightChangeActive = 0x2,
			ShouldForceCoerceSelectedItem = 0x4,
			ShouldForceCoerceSelectedValue = 0x8,
			ShouldForceCoerceHighlightedItem = 0x10,
			IsSynchronizedWithCurrentItemInternal = 0x20,
			CanExecute = 0x40,
			ShouldExecuteCommand = 0x80,
			ShouldGalleryItemsAcquireFocus = 0x100,
			HighlightChangedViaMouse = 0x200,
			FilterMenuButtonTemplateIsBound = 0x400,
		}

		// Packed boolean information
		private BitVector32 _bits = new BitVector32((int)Bits.ShouldExecuteCommand | (int)Bits.ShouldGalleryItemsAcquireFocus);
		private Collection<RibbonGalleryItem> _selectedContainers = new Collection<RibbonGalleryItem>();
		private RibbonGalleryItem _highlightedContainer;

		// Filtering
		private ObservableCollection<object> _categoryFilters = new ObservableCollection<object>();
		private static object _allFilter = SR.Get(SRID.RibbonGallery_AllFilter);
		private const string _filterMenuButtonTemplatePartName = "PART_FilterMenuButton";
		private const string FilterContentPaneTemplatePartName = "PART_FilterContentPane";
		private const string ScrollViewerTemplatePartName = "PART_ScrollViewer";
		private const string ItemsHostPanelName = "ItemsHostPanel";
		private const string ItemsHostName = "ItemsPresenter";
		private ItemsPresenter _itemsPresenter;
		private RibbonMenuButton _filterMenuButton;
		private ContentPresenter _filterContentPane;
		private RibbonMenuItem _currentFilterItem;

		private ScrollViewer _scrollViewer;

		#endregion Data
	}
}
